package com.zzb.mail;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import javax.mail.search.AndTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.SearchTerm;

import com.zzb.util.DateUtil;
import com.zzb.util.ReadPropertiesUtil;
import com.zzb.util.StringUtil;

/**
 * 有一封邮件就需要建立一个ReciveMail对象
 */
public class EmailReciveUtil {
	private Folder folder = null;
	private Store store = null;
	private ReadPropertiesUtil rdp = new ReadPropertiesUtil("email.properties");
	private ReadPropertiesUtil rddp = new ReadPropertiesUtil(
			"defaultEmailServer.properties");
	public EmailReciveUtil(String userName, String password){
		this(userName, password, 0, null,false);
	}
	public EmailReciveUtil(String userName, String password,boolean isSSL){
		this(userName, password, 0, null,isSSL);
	}
	/**
	 * 
	 * @param userName
	 *            用户名
	 * @param password
	 *            密码
	 * @param imapPort
	 * @param imapServer
	 */
	public EmailReciveUtil(String userName, String password, int imapPort, String imapServer,boolean isSSL) {
		if(StringUtil.isEmpty(userName)){
			userName = rdp.getProperties("username");
		}
		if(StringUtil.isEmpty(password)){
			password = rdp.getProperties("password");
		}
		imapServer = getMailReciveServer(imapServer,userName);
		imapPort = Integer.valueOf(getMailRecivePort(imapPort, userName, isSSL));
		Properties props = getProperties(imapServer, imapPort+"", isSSL);
		Session session = Session.getDefaultInstance(props);
		try {
			store = session.getStore();
			store.connect(imapServer,imapPort,userName,password);
			folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

	public EmailReciveUtil(EmailReciveInfo emailInfo) {
		this(emailInfo.getUserName(), emailInfo.getPassword(), emailInfo
				.getImapPort(), emailInfo.getImapServer(),emailInfo.isSSL());
	}

	public EmailReciveUtil() {
		this("", "");
	}
	

	private Properties getProperties(String mailServerHost,
			String mailServerPort,boolean isSSL) {
		if(isSSL){
//			Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
			final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
			// Get a Properties object
			Properties props = System.getProperties();
			props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
			props.setProperty("mail.imap.socketFactory.fallback", "false");
	        props.setProperty("mail.store.protocol", "imap");  
			props.setProperty("mail.imap.port", mailServerPort);
			props.setProperty("mail.imap.socketFactory.port", mailServerPort);
			return props;
		}else{
			Properties props = System.getProperties();
	        props.setProperty("mail.store.protocol", "imap");  
			return props;
		}
	}
	private String getMailReciveServer(String mailReciveServer, String userName) {
		if (StringUtil.isEmpty(mailReciveServer)) {
			String server = userName.substring(userName.indexOf("@") + 1);
			String defaultServer = rddp.getProperties(server + ".imap");
			if (StringUtil.isEmpty(defaultServer)) {
				return "imap." + server;
			} else {
				return defaultServer;
			}
		} else {
			return mailReciveServer;
		}
	}
	private String getMailRecivePort(int mailRecivePort,String userName,boolean isSSL) {
		if (mailRecivePort == 0) {
			String server = userName.substring(userName.indexOf("@") + 1)+".imap.port";
			if(isSSL){
				String defaultPort = rddp.getProperties("ssl."+server);
				if (StringUtil.isEmpty(defaultPort)) {
					return "993";
				} else {
					return defaultPort;
				}
			}else{
				String defaultPort = rddp.getProperties(server);
				if (StringUtil.isEmpty(defaultPort)) {
					return "143";
				} else {
					return defaultPort;
				}
			}
		} else {
			return mailRecivePort+"";
		}
	}
	public Message[] getMessages() {
		try {
			return folder.getMessages();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Message getLastMessages() {
		try {
			return folder.getMessage(folder.getMessageCount());
		} catch (MessagingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获得发件人的地址和姓名
	 */
	public String getFrom(Message message) throws Exception {
		InternetAddress address[] = (InternetAddress[]) message.getFrom();
		String from = StringUtil.optString(address[0].getAddress(), "");
		String personal = StringUtil.optString(address[0].getPersonal(),
				from);
		String fromaddr = personal + "<" + from + ">";
		return fromaddr;
	}

	/**
	 * 获得邮件的收件人，抄送，和密送的地址和姓名，根据所传递的参数的不同 "to"----收件人 "cc"---抄送人地址 "bcc"---密送人地址
	 */
	public String getMailAddress(String type, Message message) throws Exception {
		String mailaddr = "";
		String addtype = type.toUpperCase();
		InternetAddress[] addresses = null;
		if (addtype.equals("TO")) {
			addresses = (InternetAddress[]) message
					.getRecipients(Message.RecipientType.TO);
		} else if (addtype.equals("CC")) {
			addresses = (InternetAddress[]) message
					.getRecipients(Message.RecipientType.CC);
		} else if (addtype.equals("BCC")) {
			addresses = (InternetAddress[]) message
					.getRecipients(Message.RecipientType.BCC);
		} else {
			throw new Exception("Error emailaddr type!");
		}
		if (addresses != null) {
			for (InternetAddress address : addresses) {
				String email = address.getAddress();
				if (email == null)
					email = "";
				else {
					email = MimeUtility.decodeText(email);
				}
				String personal = address.getPersonal();
				if (personal == null)
					personal = "";
				else {
					personal = MimeUtility.decodeText(personal);
				}
				String compositeto = StringUtil.optString(personal,
						email) + "<" + email + ">";
				mailaddr += "," + compositeto;
			}
			mailaddr = mailaddr.substring(1);
		}
		return mailaddr;
	}

	/**
	 * 获得邮件主题
	 * 
	 * @throws UnsupportedEncodingException
	 */
	public String getSubject(Message message) throws MessagingException,
			UnsupportedEncodingException {
		return StringUtil.optString(MimeUtility.decodeText(message
				.getSubject()));
	}

	/**
	 * 获得邮件发送日期
	 */
	public String getSentDate(String mask, Message message) throws Exception {
		return DateUtil.getStringFromDateAsMask(mask, message.getSentDate());
	}

	/**
	 * 解析邮件，把得到的邮件内容保存到一个StringBuffer对象中，解析邮件 主要是根据MimeType类型的不同执行不同的操作，一步一步的解析
	 */
	public String getMailContent(Part part) throws Exception {
		StringBuilder str = new StringBuilder();
		String contenttype = part.getContentType();
		boolean conname = contenttype.indexOf("name") != -1;
		if (part.isMimeType("text/plain") && !conname) {
			str.append((String) part.getContent());
		} else if (part.isMimeType("text/html") && !conname) {
			str.append((String) part.getContent());
		} else if (part.isMimeType("message/rfc822")) {
			str.append(getMailContent((Part) part.getContent()));
		} else if (part.isMimeType("multipart/*")) {
			Multipart multipart = (Multipart) part.getContent();
			int counts = multipart.getCount();
			for (int i = 0; i < counts; i++) {
				str.append(getMailContent(multipart.getBodyPart(i)));
			}
		} else {
		}
		return str.toString();
	}

	/**
	 * 判断此邮件是否需要回执，如果需要回执返回"true",否则返回"false"
	 */
	public boolean getReplySign(Message message) throws MessagingException {
		return message.getHeader("Disposition-Notification-To") != null;
	}

	/**
	 * 【判断此邮件是否已读，如果未读返回返回false,反之返回true】
	 */
	public boolean isReaded(Message message) throws MessagingException {
		return message.isSet(Flag.SEEN);
	}

	/**
	 * 判断此邮件是否包含附件
	 */
	public boolean isContainAttach(Part part) throws Exception {
		if (part.isMimeType("multipart/*")) {
			Multipart mp = (Multipart) part.getContent();
			for (int i = 0; i < mp.getCount(); i++) {
				BodyPart mpart = mp.getBodyPart(i);
				String disposition = mpart.getDisposition();
				if ((disposition != null)
						&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
								.equals(Part.INLINE))))
					return true;
				else if (mpart.isMimeType("multipart/*")) {
					return isContainAttach(mpart);
				} else {
					String contype = mpart.getContentType();
					if (contype.toLowerCase().indexOf("application") != -1)
						return true;
					if (contype.toLowerCase().indexOf("name") != -1)
						return true;
				}
			}
		} else if (part.isMimeType("message/rfc822")) {
			return isContainAttach((Part) part.getContent());
		}
		return false;
	}

	/**
	 * 【保存附件】
	 */
	public void saveAttachMent(String savePath, Part part) throws Exception {
		String fileName = "";
		if (part.isMimeType("multipart/*")) {
			Multipart mp = (Multipart) part.getContent();
			for (int i = 0; i < mp.getCount(); i++) {
				BodyPart mpart = mp.getBodyPart(i);
				String disposition = mpart.getDisposition();
				if ((disposition != null)
						&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
								.equals(Part.INLINE)))) {
					fileName = mpart.getFileName();
					if ((fileName != null)
							&& fileName.toLowerCase().indexOf("gb2312") != -1) {
						fileName = MimeUtility.decodeText(fileName);
					}
					if(fileName != null){
						saveFile(savePath, fileName, mpart.getInputStream());
					}
				} else if (mpart.isMimeType("multipart/*")) {
					saveAttachMent(savePath, mpart);
				} else {
					fileName = mpart.getFileName();
					if ((fileName != null)
							&& (fileName.toLowerCase().indexOf("GB2312") != -1)) {
						fileName = MimeUtility.decodeText(fileName);
						saveFile(savePath, fileName, mpart.getInputStream());
					}
				}
			}
		} else if (part.isMimeType("message/rfc822")) {
			saveAttachMent(savePath, (Part) part.getContent());
		}
	}

	/**
	 * 【真正的保存附件到指定目录里】
	 */
	private void saveFile(String savePath, String fileName, InputStream in)
			throws Exception {
		String osName = StringUtil.optString(
				System.getProperty("os.name"), "");
		if (osName.toLowerCase().indexOf("win") != -1) {
			savePath = StringUtil.optString(savePath.replace("/", "\\"),
					"c:\\tmp\\");
			savePath += savePath.endsWith("\\") ? "" : "\\";
		} else {
			savePath = StringUtil.optString(savePath.replace("\\", "/"),
					"/tmp/");
			savePath += savePath.endsWith("/") ? "" : "/";
		}
		File storefile = new File(savePath + fileName);
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;
		try {
			bos = new BufferedOutputStream(new FileOutputStream(storefile));
			bis = new BufferedInputStream(in);
			byte[] bytes = new byte[1024];
			while (bis.read(bytes) != -1) {
				bos.write(bytes);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("文件保存失败!");
		} finally {
			bos.flush();
			bos.close();
			bis.close();
		}
	}

	public void close() {
		try {
			if (store != null) {
				store.close();
			}
			if (folder != null) {
				folder.close(false);
			}
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * PraseMessage类测试
	 */
	public static void main(String args[]) throws Exception {
		String userName = "zhzhbin1030@hotmail.com";
		String password = "54a12326";
		EmailReciveUtil pmm = new EmailReciveUtil(userName, password,true);
		/*
		 * uid获取邮件 FetchProfile profile = new FetchProfile();
		 * profile.add(UIDFolder.FetchProfileItem.UID);
		 * profile.add(FetchProfile.Item.ENVELOPE); if (pmm.folder instanceof
		 * IMAPFolder) { IMAPFolder inbox = (IMAPFolder) pmm.folder; Message
		 * message[] = inbox.getMessages();
		 * System.out.println("Messages's　length:　" + message.length); for (int
		 * i = 0; i < message.length; i++) { MimeMessage mimeMessage =
		 * (MimeMessage) message[i]; long uid = inbox.getUID(mimeMessage);
		 * System.out.println(i+"uid=" + uid); int UnreadMessageCount =
		 * inbox.getUnreadMessageCount();
		 * System.out.println("UnreadMessageCount="+UnreadMessageCount); int
		 * NewMessageCount = inbox.getNewMessageCount();
		 * System.out.println("NewMessageCount="+NewMessageCount); URLName
		 * urlName = inbox.getURLName(); System.out.println("urlName="+urlName);
		 * 
		 * } }
		 */
		SearchTerm st = new AndTerm(new ReceivedDateTerm(ComparisonTerm.GE,
				DateUtil.getDateFromStringAsMask(DateUtil.YYYYMMDD,
						"2013-03-13")), new ReceivedDateTerm(ComparisonTerm.LE,
				new Date()));
		Message message[] = pmm.folder.search(st);
		for (int i = 0; i < message.length; i++) {
			System.out.println("======================");
			System.out.println("Message " + i + " subject: "
					+ pmm.getSubject(message[i]));
			System.out.println("Message " + i + " sentdate: "
					+ pmm.getSentDate("yy年MM月dd日 HH:mm", message[i]));
			System.out.println("Message " + i + " replysign: "
					+ pmm.getReplySign(message[i]));
			System.out.println("Message " + i + " hasRead: "
					+ pmm.isReaded(message[i]));
			System.out.println("Message " + i + "containAttachment: "
					+ pmm.isContainAttach(message[i]));
			System.out.println("Message " + i + " form: "
					+ pmm.getFrom(message[i]));
			System.out.println("Message " + i + " to: "
					+ pmm.getMailAddress("to", message[i]));
			System.out.println("Message " + i + " cc: "
					+ pmm.getMailAddress("cc", message[i]));
			System.out.println("Message " + i + " bcc: "
					+ pmm.getMailAddress("bcc", message[i]));
			System.out.println("Message " + i + " sentdate: "
					+ message[i].getSentDate());
			// 获得邮件内容===============
			System.out.println("Message " + i + " bodycontent: \r\n"
					+ pmm.getMailContent(message[i]));
			pmm.saveAttachMent("c:\\", message[i]);
		}
		System.out.println(pmm.folder.getNewMessageCount());
		System.out.println(pmm.folder.getMessageCount());
		System.out.println(pmm.folder.getUnreadMessageCount());
		/*
		 * Message message[] = pmm.folder.getMessages(new int[]{14,15});
		 * System.out.println("Messages's length: " + message.length); for (int
		 * i = 0; i < message.length; i++) {
		 * System.out.println("======================");
		 * System.out.println("Message " + i + " subject: " +
		 * pmm.getSubject(message[i])); System.out.println("Message " + i +
		 * " sentdate: "+ pmm.getSentDate("yy年MM月dd日 HH:mm",message[i]));
		 * System.out.println("Message " + i + " replysign: "+
		 * pmm.getReplySign(message[i])); System.out.println("Message " + i +
		 * " hasRead: " + pmm.isReaded(message[i]));
		 * System.out.println("Message " + i + "containAttachment: "+
		 * pmm.isContainAttach((Part) message[i]));
		 * System.out.println("Message " + i + " form: " +
		 * pmm.getFrom(message[i])); System.out.println("Message " + i +
		 * " to: "+ pmm.getMailAddress("to",message[i]));
		 * System.out.println("Message " + i + " cc: "+
		 * pmm.getMailAddress("cc",message[i])); System.out.println("Message " +
		 * i + " bcc: "+ pmm.getMailAddress("bcc",message[i]));
		 * System.out.println("Message " + i + " sentdate: "+
		 * message[i].getSentDate()); System.out.println("Message " + i +
		 * " Message-ID: "+ ((MimeMessage)message[i]).getMessageID()); //
		 * 获得邮件内容=============== System.out.println("Message " + i +
		 * " bodycontent: \r\n" + pmm.getMailContent((Part) message[i]));
		 * pmm.saveAttachMent("c:\\",(Part) message[i]); }
		 */
		/*
		 * Message message[] = pmm.getMessages();
		 * System.out.println("Messages's length: " + message.length); for (int
		 * i = 0; i < message.length; i++) {
		 * System.out.println("======================");
		 * System.out.println("Message " + i + " subject: " +
		 * pmm.getSubject(message[i])); System.out.println("Message " + i +
		 * " sentdate: "+ pmm.getSentDate("yy年MM月dd日 HH:mm",message[i]));
		 * System.out.println("Message " + i + " replysign: "+
		 * pmm.getReplySign(message[i])); System.out.println("Message " + i +
		 * " hasRead: " + pmm.isReaded(message[i]));
		 * System.out.println("Message " + i + "containAttachment: "+
		 * pmm.isContainAttach((Part) message[i]));
		 * System.out.println("Message " + i + " form: " +
		 * pmm.getFrom(message[i])); System.out.println("Message " + i +
		 * " to: "+ pmm.getMailAddress("to",message[i]));
		 * System.out.println("Message " + i + " cc: "+
		 * pmm.getMailAddress("cc",message[i])); System.out.println("Message " +
		 * i + " bcc: "+ pmm.getMailAddress("bcc",message[i]));
		 * System.out.println("Message " + i + " sentdate: "+
		 * message[i].getSentDate()); System.out.println("Message " + i +
		 * " Message-ID: "+ ((MimeMessage)message[i]).getMessageID()); //
		 * 获得邮件内容=============== System.out.println("Message " + i +
		 * " bodycontent: \r\n" + pmm.getMailContent((Part) message[i]));
		 * pmm.saveAttachMent("c:\\",(Part) message[i]); }
		 */
		System.out.println(pmm.getSubject(pmm
				.getLastMessages()));
	}
}
